package com.qqt.csr.route.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.qqt.csr.common.exception.StatusCode;
import com.qqt.csr.common.utils.CacheKeyUtil;
import com.qqt.csr.common.utils.RedissonLockUtil;
import com.qqt.csr.common.utils.ServiceAssert;
import com.qqt.csr.route.dto.req.CreatingRouteTaskDTO;
import com.qqt.csr.route.dto.resp.CreatingRouteTaskRespDTO;
import com.qqt.csr.route.entity.RouteDistributionRule;
import com.qqt.csr.route.entity.RouteTask;
import com.qqt.csr.route.enums.RouteTaskEventEnum;
import com.qqt.csr.route.enums.RouteTaskStatusEnum;
import com.qqt.csr.route.mapper.mongo.RouteTaskMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class RouteTaskService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private RouteTaskMapper routeTaskMapper;
    @Autowired
    private RouteDistributionRuleService routeDistributionRuleService;
    @Autowired
    private ServiceTimeService serviceTimeService;
    @Autowired
    private RouteMqProducerService routeMqProducerService;
    @Autowired
    private RedissonLockUtil redissonLockUtil;

    /**
     * 保存路由任务
     *
     * @param routeTask
     */
    public void save(RouteTask routeTask) {
        routeTaskMapper.save(routeTask);
    }

    /**
     * 保存路由任务
     *
     * @param routeTaskList
     */
    public void save(List<RouteTask> routeTaskList) {
        routeTaskMapper.saveAll(routeTaskList);
    }

    /**
     * 根据任务id查询路由任务
     *
     * @param idList
     * @return
     */
    public List<RouteTask> getListBy(List<String> idList) {
        Criteria criteria = Criteria.where("id").in(idList);
        Query query = Query.query(criteria);
        return mongoTemplate.find(query, RouteTask.class);
    }

    /**
     * 根据租户id、渠道id、渠道用户id查询路由任务
     *
     * @param accountId
     * @return
     */
    public RouteTask findLastBy(String accountId) {
        Criteria criteria = Criteria.where("accountId").is(accountId);
        Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
        Query query = Query.query(criteria).with(sort).limit(1);
        List<RouteTask> routeTasks = mongoTemplate.find(query, RouteTask.class);
        if (CollectionUtils.isEmpty(routeTasks)) {
            return null;
        }
        return routeTasks.get(0);
    }

    /**
     * 访客进线创建路由任务
     *
     * @param creatingRouteTaskDTO
     * @return
     */
    public CreatingRouteTaskRespDTO createTask(CreatingRouteTaskDTO creatingRouteTaskDTO) {
        String lockKey = String.format(CacheKeyUtil.CsrRoute.CREATE_ROUTE_TASK_LOCK, creatingRouteTaskDTO.getConversationId());
        return redissonLockUtil.distributedLock(() -> {
            RouteTask existTask = findLastBy(creatingRouteTaskDTO.getAccountId());
            if (existTask != null && !RouteTaskStatusEnum.FAIL.equals(existTask.getStatus())
                    && !RouteTaskStatusEnum.ROUTED.equals(existTask.getStatus())) {
                // 返回信息
                return CreatingRouteTaskRespDTO.of(existTask.getId(), existTask.getStatus());
            }

            // 获取路由规则信息
            RouteDistributionRule routeRule = routeDistributionRuleService.queryById(creatingRouteTaskDTO.getRouteId());
            ServiceAssert.notNull(routeRule, StatusCode.Common.NOT_EXIST.getCode(), "转人工失败，路由已删除！", String.format("渠道未配置路由，channelId:%s,routeId:%s", creatingRouteTaskDTO.getChannelId(), creatingRouteTaskDTO.getRouteId()));
            ServiceAssert.isTrue(CollectionUtils.isNotEmpty(routeRule.getRouteBizRuleList()), StatusCode.Common.NOT_EXIST.getCode(), "转人工失败，配置异常！", String.format("未配置业务规则，channelId:%s,routeId:%s", creatingRouteTaskDTO.getChannelId(), creatingRouteTaskDTO.getRouteId()));
            ServiceAssert.isTrue(routeRule.isEnable(), StatusCode.Common.DISABLE_ERROR.getCode(), "转人工失败，路由关闭！", String.format("路由规则已被禁用，channelId:%s,routeId:%s", creatingRouteTaskDTO.getChannelId(), creatingRouteTaskDTO.getRouteId()));

            RouteTask routeTask = RouteTask.create(creatingRouteTaskDTO, routeRule);

            // 是否在当前服务时间
            Date currentTime = new Date();
            boolean isWorkTime = serviceTimeService.match(routeTask.getTenantId(), routeRule.getBizTimeId(), currentTime);
            if (!isWorkTime) {
                // 返回提示
                routeTask.addEvent(RouteTaskEventEnum.NOT_MATCHED_TIME);
                save(routeTask);
                return CreatingRouteTaskRespDTO.of(routeTask.getId(), routeRule.getRestTimeInTip(), routeTask.getStatus());
            }

            save(routeTask);
            // 异步路由分发
            routeMqProducerService.sendRouteTask(routeTask);

            return CreatingRouteTaskRespDTO.of(routeTask.getId(), routeTask.getStatus());
        }, lockKey, 30, 1, TimeUnit.MINUTES);

    }

    /**
     * 更具会话id查询路由任务
     *
     * @param conversationId
     * @return
     */
    public RouteTask queryByConversationId(String conversationId, RouteTaskStatusEnum statusEnum) {
        return queryByConversationId(conversationId, Lists.newArrayList(statusEnum));
    }

    /**
     * 更具会话id查询路由任务
     *
     * @param conversationId
     * @return
     */
    public RouteTask queryByConversationId(String conversationId, List<RouteTaskStatusEnum> statusList) {
        Criteria criteria = Criteria.where("conversationId").is(conversationId);
        if(CollectionUtils.isNotEmpty(statusList)){
            if(statusList.size()==1){
                criteria.and("status").is(statusList.get(0).name());
            }else{
                criteria.and("status").in(statusList.stream().map(RouteTaskStatusEnum::name).collect(Collectors.toList()));
            }
        }

        Query query = Query.query(criteria).with(Sort.by(Sort.Direction.DESC, "createTime")).limit(1);
        List<RouteTask> routeTasks = mongoTemplate.find(query, RouteTask.class);
        if (CollectionUtils.isEmpty(routeTasks)) {
            return null;
        }
        return routeTasks.get(0);
    }

    /**
     * 根据会话id查询路由任务
     *
     * @param conversationIdList
     * @param statusEnum
     * @return
     */
    public Map<String, RouteTask> queryByConversationId(List<String> conversationIdList, RouteTaskStatusEnum statusEnum) {
        if (CollectionUtils.isEmpty(conversationIdList)) {
            return Maps.newHashMap();
        }

        Criteria criteria = Criteria.where("conversationId").in(conversationIdList)
                .and("status").is(statusEnum.name());
        Query query = Query.query(criteria).with(Sort.by(Sort.Direction.DESC, "createTime"));
        List<RouteTask> routeTasks = mongoTemplate.find(query, RouteTask.class);
        if (CollectionUtils.isEmpty(routeTasks)) {
            return Maps.newHashMap();
        }
        return routeTasks.stream().collect(Collectors.toMap(RouteTask::getConversationId, v -> v, (o, n) -> n));
    }
}
